#pragma once

#include<iostream>
#include <sched.h>
#include <string>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include"../comm/util.hpp"
#include"../comm/log.hpp"

namespace ns_runner 
{
    using namespace ns_util;
    using namespace ns_log;//..1

    class Runner
    {
        public:
        Runner()
        {}
        ~Runner()
        {}

        static void SetProcLimit(int cpu_limit,int mem_limit)//以kb为单位
        {
            //设置cpu资源上限
            struct rlimit c_rlimit;
            c_rlimit.rlim_max=RLIM_INFINITY;
            c_rlimit.rlim_cur=cpu_limit;
            setrlimit(RLIMIT_CPU, &c_rlimit);
            //设置占用内存上限
             struct rlimit m_rlimit;
            m_rlimit.rlim_max=RLIM_INFINITY;
            m_rlimit.rlim_cur=mem_limit * 1024;//以kb为单位
            setrlimit(RLIMIT_AS, &m_rlimit);
        }
        static int Run(const std::string& file_name,int cpu_limit,int mem_limit)
        {
           /* pid_t pid=fork();
            if(pid<0)
            {
                //创建子进程失败；，，

                return -1;
            }
            */

            //临时文件
            std::string _execute=Path_file::Exe(file_name);
            std::string _std_in=Path_file::Std_in(file_name);
            std::string _std_out=Path_file::Std_out(file_name);
            std::string _std_err=Path_file::Std_run_err(file_name);

            //打开文件
            umask(0);
            int std_in_fd=open(_std_in.c_str(),O_CREAT | O_RDONLY , 0644);
            int std_out_fd=open(_std_out.c_str(),O_CREAT | O_WRONLY , 0644);
            int std_err_fd=open(_std_err.c_str(),O_CREAT | O_WRONLY , 0644);
            if(std_in_fd<0||std_out_fd<0||std_err_fd<0)//?open fail
            {
                //文件打开失败
                LOG(ERROR)<<"运行时打开标准文件失败"<<"\n";
                return -1;
            }

            pid_t pid=fork();
            if(pid<0)
            {
                //创建子进程失败；，，
                LOG(ERROR)<<"运行时创建子进程失败"<<std::endl;

                close(std_in_fd);
                close(std_out_fd);
                close(std_err_fd);
                //LOG(ERROR)<<"运行时创建子进程失败"<<std::endl;

                return -2;
            }

            else if (0==pid)
            {
                //子进程程序替换执行running
                dup2(std_in_fd,0);
                dup2(std_out_fd,1);
                dup2(std_err_fd,2);
                //设置资源上限
                SetProcLimit(cpu_limit,mem_limit);
                /*close(std_in_fd);
                close(std_out_fd);
                close(std_err_fd);*/
                
                execl(_execute.c_str(),_execute.c_str(),nullptr);//?执行这个程序，，在命令行执行//注意参数传递
                //LOG(ERROR)<<"程序替换失败"<<std::endl;
                exit(3);//程序替换失败      
            }

            else
            {

                close(std_in_fd);
                close(std_out_fd);
                close(std_err_fd);
                int status=0;
                waitpid(pid, &status,0);
                //父进程
                /*close(std_in_fd);
                close(std_out_fd);
                close(std_err_fd);*/
                LOG(INFO)<<"运行完毕，Info： "<<(status & 0x7F)<<"\n";

                return status & 0x7F;//?01111111提取退出码的低7位
            }
        }
    };
}